using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using xn;
using System.Threading;

namespace StartDance
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class StartDance : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        PlayerManager playerManager;
        Thread stepGenerator;
        StepManager stepManager;
        MusicManager musicManager;
        State state;
       
        delegate void GestureHandler();
        delegate void UpdateScore(Direction dir);
        Texture2D bg, tile, tile_selected, up,down,left,right,selection, pesan1;
        SpriteFont scoreFont;

        public StartDance()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            state = State.Init;
            
            graphics.PreferredBackBufferWidth = 1024;
            graphics.PreferredBackBufferHeight = 576;

            Exiting += new EventHandler(StartDance_Exiting);

        }

        public void StartDance_Exiting(object sender, EventArgs e)
        {
            stepManager.isAlive = false;
            musicManager.StopMusic();
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            GestureHandler gestureHandler = new GestureHandler(StartGame);
            UpdateScore updateScoreDelegate = new UpdateScore(updateScore);

            playerManager = new PlayerManager(this, gestureHandler);
            stepManager = new StepManager(updateScoreDelegate);
            stepGenerator = new Thread(new ThreadStart(stepManager.generateStep));

            musicManager = new MusicManager();
            base.Initialize();
        }
        
        void StartGame()
        {
            if (state == State.Init)
            {
                stepGenerator.Start();
                musicManager.PlayMusic(this, @"music/heartofsword");
                state = State.Play;
            }
            else if (state == State.Play)
            {
                this.Exit();
            }
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            bg = Content.Load<Texture2D>("image/bg");
            tile = Content.Load<Texture2D>("image/tile");
            tile_selected = Content.Load<Texture2D>("image/tile_selected");
            up = Content.Load<Texture2D>("image/up");
            down = Content.Load<Texture2D>("image/down");
            left = Content.Load<Texture2D>("image/left");
            right = Content.Load<Texture2D>("image/right");
            selection = Content.Load<Texture2D>("image/selection");
            pesan1 = Content.Load<Texture2D>("image/pesanwave");

            scoreFont = Content.Load<SpriteFont>(@"font/courier");
            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
                Keyboard.GetState().IsKeyDown(Keys.Escape) || Keyboard.GetState().IsKeyDown(Keys.F1))
                this.Exit();

            if (state == State.Init && Keyboard.GetState().IsKeyDown(Keys.Enter))
                StartGame();


            // TODO: Add your update logic here
            playerManager.Update(gameTime);
            base.Update(gameTime);
        }

        public void updateScore(Direction dir)
        {
            //UPDATE SCORE
            if (dir == Direction.Up && Keyboard.GetState().IsKeyDown(Keys.Up) ||
                dir == Direction.Left && Keyboard.GetState().IsKeyDown(Keys.Left) ||
                dir == Direction.Right && Keyboard.GetState().IsKeyDown(Keys.Right) ||
                dir == Direction.Down && Keyboard.GetState().IsKeyDown(Keys.Down))
            {
                spriteBatch.Begin();
                spriteBatch.DrawString(scoreFont, "+100", new Vector2(196, 500), Color.YellowGreen, 0, Vector2.Zero, 2, SpriteEffects.None, 0);
                spriteBatch.End();
            }

            foreach (Player player in playerManager.playerList)
            {
                if (dir == player.getKuadran())
                {
                    player.score += 100;

                    spriteBatch.Begin();
                    spriteBatch.DrawString(scoreFont, "+100", new Vector2(196, 500), Color.YellowGreen, 0, Vector2.Zero, 2, SpriteEffects.None, 0);
                    spriteBatch.End();
                    Console.WriteLine("Score : " + player.score);
                }                
            }
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            
            // TODO: Add your drawing code here
            spriteBatch.Begin();
            spriteBatch.Draw(bg, new Vector2(0,0),Color.White);

            //DRAW PLAYER POSITION & SELECTION
            Point topleft = new Point(412, 150);
            for (int i = 0; i < 3; i++) //baris
                for (int j = 0; j < 3; j++)//kolom
                {
                    Rectangle rect = new Rectangle(topleft.X + 67 * j, topleft.Y + 67 * i, 67, 67);
                    spriteBatch.Draw(tile, rect, Color.CornflowerBlue);
                }

            if (playerManager.playerList.Count > 0)
            {
                Direction kuadran = playerManager.playerList[0].getKuadran();
                Rectangle rect;
                switch (kuadran)
                {
                    case Direction.Left: rect = new Rectangle(topleft.X, topleft.Y + 67, 67, 67); break;
                    case Direction.Down: rect = new Rectangle(topleft.X + 67, topleft.Y + 67 * 2, 67, 67); break;
                    case Direction.Up: rect = new Rectangle(topleft.X + 67, topleft.Y, 67, 67); break;
                    case Direction.Right: rect = new Rectangle(topleft.X + 67 * 2, topleft.Y + 67, 67, 67); break;
                    case Direction.LeftUp: rect = new Rectangle(topleft.X, topleft.Y, 67, 67); break;
                    case Direction.LeftDown: rect = new Rectangle(topleft.X, topleft.Y + 67 * 2, 67, 67); break;
                    case Direction.RightUp: rect = new Rectangle(topleft.X + 67 * 2, topleft.Y, 67, 67); break;
                    case Direction.RightDown: rect = new Rectangle(topleft.X + 67 * 2, topleft.Y + 67 * 2, 67, 67); break;
                    case Direction.Center: rect = new Rectangle(topleft.X + 67, topleft.Y + 67, 67, 67); break;
                    default: rect = new Rectangle(-1000, -1000, 0, 0); break;
                }
                spriteBatch.Draw(tile_selected, rect, Color.White);
                
                //Rectangle rect2;
                //switch (kuadran)
                //{
                //    case Direction.Left: rect2 = new Rectangle(100, 176, 48, 360); break;
                //    case Direction.Down: rect2 = new Rectangle(100 + 48, 176, 48, 360); break;
                //    case Direction.Up: rect2 = new Rectangle(100 + 48 * 2, 176, 48, 360); break;
                //    case Direction.Right: rect2 = new Rectangle(100 + 48 * 3, 176, 48, 360); break;
                //    default: rect2 = new Rectangle(0, 0, 0, 0); break;
                //}
                //spriteBatch.Draw(selection, rect2, Color.White);
            }
            /*foreach (Player player in playerManager.playerList)
            {
                Rectangle rect = new Rectangle(412 + 100 + (int)player.position.X * 2 / 9, 38 + (int)(player.position.Z - Player.KINECT_DISTANCE) * 2 / 9, 30, 30);                
                spriteBatch.Draw(playerManager.picture, rect, Color.CornflowerBlue);
            }*/

            //DRAW STEP
            for (int i = 0; i < stepManager.stepList.Count; i++)
            {
                Step s = stepManager.stepList[i];
                int pengali;
                switch (s.dir)
                {
                    case Direction.Left: pengali = 0; break;
                    case Direction.Down: pengali = 1; break;
                    case Direction.Up : pengali = 2; break;
                    case Direction.Right: pengali = 3; break;
                    default: pengali = -1000; break;
                }

                Vector2 pos = new Vector2(100 + (pengali * 48), 576 - 100 - i * 60);
                switch (pengali)
                {
                    case 0: spriteBatch.Draw(left, pos, Color.White); break;
                    case 1: spriteBatch.Draw(down, pos, Color.White); break;
                    case 2: spriteBatch.Draw(up, pos, Color.White); break;
                    case 3: spriteBatch.Draw(right, pos, Color.White); break;
                }
                //pos = new Vector2(712 + (pengali * 48), 576 - 100 - i * 60);
                //switch (pengali)
                //{
                //    case 0: spriteBatch.Draw(left, pos, Color.White); break;
                //    case 1: spriteBatch.Draw(down, pos, Color.White); break;
                //    case 2: spriteBatch.Draw(up, pos, Color.White); break;
                //    case 3: spriteBatch.Draw(right, pos, Color.White); break;
                //}
            }

            //KEYBOARD EVENT
            if (Keyboard.GetState().IsKeyDown(Keys.Left))
            {
                Rectangle rect2 = new Rectangle(100, 176, 48, 360);
                spriteBatch.Draw(selection, rect2, Color.White);
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Down))
            {
                Rectangle rect2 = new Rectangle(100 + 48, 176, 48, 360);
                spriteBatch.Draw(selection, rect2, Color.White);
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Up))
            {
                Rectangle rect2 = new Rectangle(100 + 48 * 2, 176, 48, 360);
                spriteBatch.Draw(selection, rect2, Color.White);
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                Rectangle rect2 = new Rectangle(100 + 48 * 3, 176, 48, 360);
                spriteBatch.Draw(selection, rect2, Color.White);
            }

            //DRAW SCORE
            foreach (Player player in playerManager.playerList)
            {
                spriteBatch.DrawString(scoreFont, String.Format("Score : {0}", player.score), new Vector2(100, 76), Color.Yellow);
            }

            //PESAN2
            if (state == State.Init)
            {
                spriteBatch.Draw(pesan1, new Rectangle(410, 240, 200, 200), Color.White);
            }
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }

    public enum State {Init,Play,End};
}
